/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.yonsei.iwb.smarttv.gui;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.vocabulary.RDF;
import edu.yonsei.iwb.smarttv.LocalOntologySearch;
import edu.yonsei.iwb.smarttv.LocalOntologySearchInterface;
import edu.yonsei.iwb.smarttv.index.IndexType;
import edu.yonsei.iwb.smarttv.index.OntologyIndexer;
import edu.yonsei.iwb.smarttv.jena.ext.JenaModelType;
import edu.yonsei.iwb.smarttv.model.ConceptualGraph;
import edu.yonsei.iwb.smarttv.model.SMARTTVModel;
import edu.yonsei.iwb.smarttv.model.measure.ResourceWeights;
import edu.yonsei.iwb.smarttv.model.measure.WeightModel;
import edu.yonsei.iwb.smarttv.model.measure.WeightModelType;
import edu.yonsei.iwb.smarttv.query.HanNanumMorphemeTag;
import edu.yonsei.iwb.smarttv.query.TermAnalyzer;
import edu.yonsei.iwb.smarttv.querygraph.DynamicSPARQLGenerator;
import edu.yonsei.iwb.smarttv.querygraph.QueryCombination;
import edu.yonsei.iwb.smarttv.querygraph.QueryCombinationSet;
import edu.yonsei.iwb.smarttv.querygraph.algorithm.ShortestPathVectorCandidateSet;
import edu.yonsei.iwb.smarttv.result.*;
import edu.yonsei.iwb.smarttv.userpreference.UserPreferenceModel;
import edu.yonsei.iwb.smarttv.userpreference.UserPreferenceModelType;
import edu.yonsei.iwb.smarttv.userpreference.UserPreferenceSearch;
import edu.yonsei.iwb.smarttv.userpreference.UserPreferenceURI;
import edu.yonsei.iwb.smarttv.util.UtilMethodSet;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;
import kr.ac.kaist.swrc.jhannanum.comm.Eojeol;
import kr.ac.kaist.swrc.jhannanum.exception.ResultTypeException;

/**
 *
 * @author Soo
 */
public class Controller {
    private String ontology;
    private SMARTTVModel tvModel;
    private OntologyIndexer oi;
    private LocalOntologySearchInterface losi;    
    private String query;
    private String id;
    private TermAnalyzer ta;
    private NERResults ner;
    private DynamicSPARQLGenerator dsg;
    private ShortestPathVectorCandidateSet spvcs;
    private Vector<String> sparqlSet;
    private String selectedSPARQLID;
    private UserPreferenceModel upModel;
    private UserPreferenceSearch ups;
    private UserPreferenceURI url;
    private HashMap<String, Double> scores;
    private Hashtable<String, String> userTable;
    
    public void selectOntFile(String ontology){
        this.ontology = ontology;
    }
    
    public void setUserID(String id) {
        this.id = id;
    }

    public void loadOntOnTDB() {
        tvModel = new SMARTTVModel(JenaModelType.TDB_MODEL);
        tvModel.loadOntology(ontology);        
    }

    public void useTDBModel(String directory) {
        JenaModelType.MODEL_DIR = directory;
        tvModel = new SMARTTVModel(JenaModelType.TDB_MODEL);
    }
    
    public void loadOntOnMemory(){
        tvModel = new SMARTTVModel(JenaModelType.MEMORY_MODEL);
        tvModel.loadOntology(ontology);
    }
    
    public void loadOntOnTDBUser() {
        upModel = new UserPreferenceModel(UserPreferenceModelType.TDB_MODEL);
        upModel.loadOntology(ontology);        
    }
  
    public void useTDBModelUser(String directory) { 
        UserPreferenceModelType.MODEL_DIR = directory;
        upModel = new UserPreferenceModel(UserPreferenceModelType.TDB_MODEL);        
    }
    
    public void loadOntOnMemoryUser(){
        upModel = new UserPreferenceModel(UserPreferenceModelType.MEMORY_MODEL);
        upModel.loadOntology(ontology);                
    }
    
    public void loadIndexOnMemory(){
        oi = new OntologyIndexer(IndexType.MEMORY_INDEX, tvModel);        
    }
    
    private void createLocalOntologySearchWithUserPreference(){
        if(CurrentProcedureInfo.USER_PROFILE_FROM_FILE){
            System.out.println("user profile from files");
            losi = new LocalOntologySearch(tvModel, upModel, UserPreferenceModelType.PROFILE_DIR, oi.getIndex());
        }else{
            System.out.println("user profile files are generated");
            losi = new LocalOntologySearch(tvModel, upModel, oi.getIndex());
        }
    }
            
    public void generateNewIndexInDir(String directory) {  
        IndexType.INDEX_DIR = directory;
        oi = new OntologyIndexer(IndexType.FILE_INDEX, tvModel);        
    }
    
    public void useFileIndex(String directory) {
        IndexType.INDEX_DIR = directory;
        oi = new OntologyIndexer();
    }
    
    public void loadWeightInDir(String directory) {        
        WeightModelType.FILEADDRESS = directory;
    }
    
    public void useFileWeight(String directory) {
        WeightModelType.FILEADDRESS = directory;
    }
    
    public int initializeLocalSearchOntology(){
        if(CurrentProcedureInfo.SEARCH_ONTOLOGY_LOADED){
            if(CurrentProcedureInfo.SEARCH_INDEX_LOADED){                
                if(CurrentProcedureInfo.WEIGHT_LOADED){
                    if(CurrentProcedureInfo.USER_ONTOLOGY_LOADED){
                        createLocalOntologySearchWithUserPreference();
                        return CurrentProcedureInfo.READY;
                    }else{
                        this.losi = new LocalOntologySearch(tvModel, oi.getIndex());
                        return CurrentProcedureInfo.READY;
                    }
                }else{
                    return CurrentProcedureInfo.NO_WEIGHT;
                }
            }else{
                return CurrentProcedureInfo.NO_SEARCH_INDEX;
            }
        }else{
            return CurrentProcedureInfo.NO_SEARCH_ONTOLOGY;
        }
    }
    
    /**
     * 형태소 분석 수행 후 결과 리턴
     * @param query 사용자 질의
     * @return 형태소 분석 결과
     */
    public Vector<String[]> getMAResult(String query) {
        this.query = query;
        Vector<String[]> maVector = new Vector<String[]>();
        ta = new TermAnalyzer();
        Eojeol[] maResult;
        try {
            maResult = ta.getEojeol(this.query);
            for (int i = 0; i < maResult.length; i++) {
                if (maResult[i].length > 0) {
                    String[] morphemes = maResult[i].getMorphemes();
                    String[] tags = maResult[i].getTags();
                    for (int j = 0; j < morphemes.length; j++) {
                        if (HanNanumMorphemeTag.useMorpheme(tags[j])) {
                            String[] s ={morphemes[j].toLowerCase(), tags[j]};
                            maVector.add(s);
                        }
                    }
                }
            }
        } catch (ResultTypeException ex) {
            Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
        }
        ta.deactivateWorkflow();
        return maVector;
    }
    
    public Vector<String[]> getNERResult(Vector<String> indexTerms){ 
        Vector<String[]> nerVector = new Vector<String[]>();
        this.ner = losi.recognizeNamedEntity(this.query, indexTerms);
        NamedEntitySetByKeyword nelhm = ner.getNamedEntityResults();
        Iterator<String> keyIterator = nelhm.getKeywordsSet().iterator();
        while (keyIterator.hasNext()) {
            String key = keyIterator.next();
            NamedEntitySet nes = ner.getNamedEntitySetByString(key);
            for (int i = 0; i < nes.size(); i++) {
                NamedEntity ne = nes.get(i);
                ResultTypeInfo rti = ne.getResultTypes();
                for (int j = 0; j < rti.size(); j++) {
                    ResultNode resultNode = rti.get(j);
                    String keyword = key;
                    String[] uri =  ne.getNamedEntityNodeId().split("/");
                    String lastUri = uri[uri.length-1];
                    String label = ne.getNamedEntityNodeLabel();                    
                    String[] typeUri = resultNode.getResultNodeId().split("/");
                    String lastTypeUri = typeUri[typeUri.length-1];
                    String[] s ={keyword, lastUri, label, lastTypeUri};
                    nerVector.add(s);
                }
            }
        }
        return nerVector;
    }
    
    // ====================================== QueryCombination GUI 화면 보여줌 ===================================== 
    public Vector<QueryCombination> queryConbinationSet(){
        
        Vector<QueryCombination> qcs = new Vector<QueryCombination>();
        this.dsg = new DynamicSPARQLGenerator(tvModel, upModel);
        QueryCombinationSet combinationQuerySet = this.dsg.makeQueryCombinationSet(ner);
        combinationQuerySet.orderByScore(this.upModel.getWeightModel());
        
        for (Iterator<QueryCombination> it = combinationQuerySet.iterator(); it.hasNext();) {
            QueryCombination queryCombination = it.next();
            qcs.add(queryCombination);
        }
        return qcs;
    }
// ====================================== QueryCombination GUI 화면 보여줌 ===================================== 
    
    
    public LinkedHashMap<String, JPanel> getConceptualGraphViewSet() {
        this.dsg = new DynamicSPARQLGenerator(tvModel, upModel);
        this.spvcs = dsg.dynamicSPARQLGenerator(ner);
  
//        this.dsg = new DynamicSPARQLGenerator(this.tvModel);
//        this.spvcs = new ShortestPathVectorCandidateSet();
//                
//        QueryCombinationSet qcs = this.dsg.makeQueryCombinationSet(ner);
//        if(CurrentProcedureInfo.USERPREFERENCE_USER){
//            qcs.orderByScore(this.upModel.getWeightModel());            
//        }
//       
//        for (int i = 0; i < qcs.size(); i++) {
//            QueryCombination qc = qcs.get(i);
//            this.spvcs.addAll(dsg.dynamicSPARQLGenerator(qc));
//        }
        
        Vector<ConceptualGraph> conceptualGraphSet = dsg.getConceptualTreeSet();
        ConceptualGraphView cgv = new ConceptualGraphView();
//        Vector<JPanel> conceptualGraphView = cgv.generateConceptualGraphView();
        LinkedHashMap<String, JPanel> conceptualGraphView = cgv.generateConceptualGraphView(conceptualGraphSet);
        
        return conceptualGraphView;
        
    }
    
//    public Vector<JPanel> getSpanningTreeViewSet(){
//        SpanningTreeView stv = new SpanningTreeView(spvcs);
//        Vector<JPanel> spanningTreeView = stv.generateSpanningTreeView();
//        return spanningTreeView;
//    }
    
    public LinkedHashMap<String[], JPanel> getShortestPathViewSet() {
        ShortestPathView spv = new ShortestPathView(spvcs);
        LinkedHashMap<String[], JPanel> shortestPathView = spv.generateShortestPathView();
        return shortestPathView;
    }
    
    public void updataUserPreferenceWeight(String id){
        this.id = id;
        this.losi.getUserPreferenceSearch().initializeUserProfile(this.id); // 사용자 정보를 초기화하여 가중치 업데이트
        
    }

//    public Vector<JPanel> getShortestPathViewSet(){
//        ShortestPathView spv = new ShortestPathView(spvcs);
//        Vector<JPanel> shortestPathView = spv.generateShortestPathView();
//        return shortestPathView;
//    }
    
//    public Vector<String> getSPARQLViewSet(){
//        sparqlSet = new Vector<String>();
//        for(int i = 0; i < spvcs.size(); i++){
//            Query query = dsg.generateSPARQL(spvcs.get(i));
//            String sparql = query.serialize();
//            sparqlSet.add(sparql);
//        }
//        return sparqlSet;        
//    }
    
    public LinkedHashMap<String, String> getSPARQLViewSet() {
        Vector<SearchResultSet> srs = new Vector<SearchResultSet>();
        LinkedHashMap<String, Query> querySet = new LinkedHashMap<String, Query>();
        LinkedHashMap<String, String> sparqlSet = new LinkedHashMap<String, String>();
        this.scores = new HashMap<String, Double>();
        for (int i = 0; i < spvcs.size(); i++) {
            String queryID = spvcs.get(i).getSPID();
            Query query = dsg.generateSPARQL(spvcs.get(i));
            String sparql = query.serialize();
            querySet.put(queryID, query);
            sparqlSet.put(queryID, sparql);
            scores.put(queryID, spvcs.get(i).getScore());
        }
        Iterator qi = querySet.keySet().iterator();
        while (qi.hasNext()) {
            String key = qi.next().toString();
            srs = losi.getSearchResult(querySet.get(key));            
            if (!srs.isEmpty()) {
                selectedSPARQLID = key;
                break;
            }
        }
        return sparqlSet;
    }
    public HashMap<String, Double> getScore(){
        return this.scores;
    }
//    public Vector<String[]> getSearchResult(){
//        Vector<String[]> searchResultVector = new Vector<String[]>();
//        String sparql = sparqlSet.firstElement();
//        searchResultVector = getSearchResultBySPARQL(sparql);
//        return searchResultVector;
//    }
    
    public Vector<String[]> getSearchResultBySelectedQuery(String sparqlQuery){
        
        Vector<String[]> searchResultVector = new Vector<String[]>();
        searchResultVector = getSearchResultBySPARQL(sparqlQuery);
        return searchResultVector;
    }
    
    public String getSelectedSPARQLID() {
        return this.selectedSPARQLID;
    }
    
    public Vector<String[]> getSearchResultBySPARQL(String sparqlQuery){
        Vector<String[]> searchResultVector = new Vector<String[]>();
        Query query = QueryFactory.create(sparqlQuery);
        Vector<SearchResultSet> srs = losi.getSearchResult(query);        
        if(CurrentProcedureInfo.USER_ASSIGNED){
            losi.searchResultSorting(srs,true);
        } else {
            losi.searchResultSorting(srs,false);
        }
        
        // Weight 값 계산 =================================================
        WeightModel wm = tvModel.getWeightModel();
        ResourceWeights rw = wm.getOriginalOntologyWeight();
        double Weight = 0.0;
         // ============= =================================================
        
        for(int i = 0; i < srs.size(); i++){
            String title = srs.get(i).getResultLabel();
            
            // Weight 값 계산 =================================================
            if(!CurrentProcedureInfo.USER_ASSIGNED){
                SearchResultSet rrs = srs.get(i);
                Resource result = rrs.getResult().getResultNode();
                Weight = rw.get(result);
            } else {
                Weight = srs.get(i).getScore();
            }
             // ===============================================================
            
            String type = "";
            ResultTypeInfo types = srs.get(i).getResultTypes();
            for(int j = 0; j < types.size(); j++){
                String t = types.get(j).getLabel();
                if(j!=types.size()-1){
                    type += t+"/";
                }else{
                    type += t;
                }
            }
            String[] s ={Integer.toString(i+1), title, type, Weight+""};
            searchResultVector.add(s);
        }
        return searchResultVector;
    }
    
    
    public Vector<String> getUserList() {
        Vector<String> userList = new Vector<String>();
        this.userTable = new Hashtable<String,String>();        
        StmtIterator iter = this.upModel.getUserPreferenceModel().listStatements(null, RDF.type, UserPreferenceURI.USER_PROFILE);
        
        while(iter.hasNext()){
            Statement stmt = iter.nextStatement();
            Resource user = stmt.getSubject();
            userList.add(user.getLocalName().toString());
            userTable.put(user.getLocalName().toString(), user.getURI());
        }        
        return userList;
    }
    
    public String getURIOfUSer(String id){
        return this.userTable.get(id);
    }
        
    
}
